#ifndef GRAMMARDESCRIPTOR_H
#define GRAMMARDESCRIPTOR_H
//#define DEBUGLEXER
#include "LeonardVirtualMachine.h"
#include "operation.h"
#include "rule.h"
#include "parsestream.h"
#include "primitives.h"
#include "action.h"
#include "Expression.h"
#include "DerivationTree.h"
#define ASSIGN(NAME, DEFINITION) typeof((DEFINITION)) NAME = (DEFINITION)
#define CONSTASSIGN(NAME, DEFINITION) const typeof((DEFINITION)) NAME = (DEFINITION)

class GenericGrammarDescriptor {
public:
	GenericGrammarDescriptor() { }

	Rule<>* getRoot() { return &root; }
protected:
	void setRoot(Rule<> r) { root = r; }
private:
	Rule<> root;
};

class GrammarDescriptor : public GenericGrammarDescriptor {
public:
	template<typename Parser> GrammarDescriptor(Parser* p) {
		//SIMPLY SUBTOKEN
		Range<> uppchar('A','Z');
		Range<> downchar('a','z');
		Range<> digit('0','9');
		Character<> underscore('_');
		Character<> end(0);
		Character<> space(' ');
		Character<> at('@');
		Character<> point('.');
		Character<> sum('+');
		Character<> equal('=');
		Character<> star('*');
		Character<> pw('^');
		Character<> divide('/');
		Character<> reference('&');
		Character<> semicolon(';');
		Character<> colon(',');
		Character<> lP('(');
		Character<> rP(')');
		Character<> lPQ('[');
		Character<> rPQ(']');
		Character<> lPG('{');
		Character<> rPG('}');
		Character<> minus('-');
		Character<> greater('>');
		Character<> less('<');
		String<> logicalEqual("==");
		String<> logicalNEqual("!=");
		String<> functionKeyword("function");
		String<> returnKeyword("return");
		String<> varKeyword("var");
		String<> ifKeyword("if");
		String<> whileKeyword("while");
		String<> elseKeyword("else");

		//INTEGER NUMBER COSTANT
		integer_costant = action( +(digit) >> ~point , IntegerNumber<Parser>(p) );

		//FLOAT NUMBER COSTANT
		float_costant = action( +(digit) >> point >> *(digit), FloatNumber<Parser>(p) );

		//NUMBER COSTANT
		number_costant = float_costant
				|| integer_costant;

		//VARIABLE
		variable = action( (uppchar || downchar) >> *(uppchar || downchar || digit), VariableAllocator<Parser>(p));

		//PARAMETER OF A FUNCTION
		parameterFunction = expression >> *(action(*space >> colon >> *space >> expression,  Colon<Parser>(p)) );

		//NAMEOFFUNCTION
		nameFunction = action((uppchar || downchar) >> *(uppchar || downchar || digit), NameAllocator<Parser, FunctionCallNode>(p));

		//CALL FUNCTION
		function = action( nameFunction >> *space >> lP >> +(parameterFunction) >> rP, FunctionCall<Parser>(p));

		//CALL VOID FUNCTION
		voidFunction = action( nameFunction >> *space >> lP >> *space >> rP, FunctionVoidCall<Parser>(p));

		//RETURN INSTRUCTION
		returnInstruction = action(*space >> returnKeyword >>*space >> expression >> *space >> semicolon, Return<Parser>(p));

		//IF INSTRUCTION
		ifInstruction = action(
				*space >> action (ifKeyword, InitBlock<Parser>(p)) >> *space >> lP >> *space >> expression >> *space >> rP >> *space >> lPG >> *space >> *(instruction >> *space) >> rPG
				, IfAllocator<Parser>(p));

		//ELSE INSTRUCTION
		elseInstruction = action(
				*space >> action (elseKeyword, InitBlock<Parser>(p)) >> *space >> ifKeyword >> *space >> lP >> *space >> expression >> *space >> rP >> *space >> lPG >> *space >> *(instruction >> *space) >> rPG
				, ElseAllocator<Parser>(p));

		//ELSE INSTRUCTION
		elseEndInstruction = action(
				*space >> action (elseKeyword, InitBlock<Parser>(p)) >> *space >>  lPG >> *space >> *(instruction >> *space) >> rPG
				, ElseEndAllocator<Parser>(p));

		//WHILE INSTRUCTION
		whileInstruction = action(
						*space >> action (whileKeyword, InitBlock<Parser>(p)) >> *space >> lP >> *space >> expression >> *space >> rP >> *space >> lPG >> *space >> *(instruction >> *space) >> rPG
						, WhileAllocator<Parser>(p));

		//LOAD THE INSTRUCTION
		instruction = returnInstruction
				|| ifInstruction >> (*elseInstruction) >> (!elseEndInstruction)
				|| whileInstruction
				|| action(*space >> expression >> *space >> semicolon, IntructionAllocator<Parser>(p));

		//LOAD THE TEMPLATE
		//templatePattern = action(*space >> varKeyword >> +space >> , IntructionAllocator<Parser>(p));

		//LOAD THE TYPE OF A PARAMETER
		typeName = action((uppchar || downchar) >> *(uppchar || downchar || digit), NameAllocator<Parser, TypeParameterNode>(p));

		//LOAD THE NAME OF THE PARAMETER
		nameParameter = action((uppchar || downchar) >> *(uppchar || downchar || digit), NameAllocator<Parser, ParameterNameNode>(p));

		//LOAD THE PARAMETER PATTERN
		parameterPattern = action(*space >> typeName >> +space >> nameParameter, ParameterPatternAllocator<Parser>(p));

		//LOAD THE NAME OF THE FUNCTION DEFINED
		nameFunctionDeclaration = action((uppchar || downchar) >> *(uppchar || downchar || digit), NameAllocator<Parser, FunctionNameDefinitionNode>(p));

		//FUNCTION DECLARATION
		functionDeclaration = action( nameFunctionDeclaration >> *space >> equal >> *space >> functionKeyword >> *space >> lP >> *(parameterPattern >> *space >> *(colon >> *space >> parameterPattern)) >> rP >> *space >> lPG >> *instruction >> *space >> rPG, FunctionAllocator<Parser>(p) );

		//GENERIC FACTOR
		factor = integer_costant
				|| float_costant
				|| functionDeclaration
				|| function
				|| voidFunction
				|| sum >> factor
				|| variable
				|| action( minus >> factor, UnaryMinus<Parser>(p) )
				|| (lP >> *space >> expression >> *space >> rP);

		//POWER
		power = factor >>
				*( action(*space >> pw >> *space >> factor , Power<Parser>(p) ) );

		//TIMES
		times = power >>
				*( action(*space >> star >> *space >> power , Times<Parser>(p) )
						|| action(*space >> divide >> *space >> power , Divide<Parser>(p) ) );

		//PLUS
		plus = times >>
				*( action(*space >> sum >> *space >> times , Sum<Parser>(p) )
						|| action(*space >> minus >> *space >> times , Minus<Parser>(p) ) );

		//BOOL CHARACTER
		ASSIGN(boolSymbol, action(greater || less || logicalEqual || logicalNEqual, LoadBoolSymbol<Parser>(p)));

		//BOOL OPERATION
		boolean = plus >>
				*(action(*space >> boolSymbol >> *space >> plus, Boolean<Parser>(p)));

		//EXPRESSION
		expression = boolean >>
				*( action(*space >> equal >> *space >> boolean , Equal<Parser>(p) ) ) >> *space;

#ifdef DEBUGLEXER
		expression.setName("Expression Rule");
		power.setName("PowerRule");
		plus.setName("Plus Rule");
		times.setName("Times Rule");
		factor.setName("Factor Rule");
		function.setName("Function Rule");
		variable.setName("Variable Rule");
		integer_costant.setName("Integer Rule");
		float_costant.setName("Float Rule");
		number_costant.setName("Number Rule");
		parameterFunction.setName("ParameterFunction Rule");
		nameFunction.setName("NameFunction Rule");
#endif

		setRoot(expression);
	}
private:
	Rule<> integer_costant, float_costant, number_costant, expression, times, factor, variable, power, plus, function, voidFunction, parameterFunction, nameFunction, nameFunctionDeclaration, functionDeclaration, parameterPattern, instruction, returnInstruction,
	typeName, nameParameter, boolean, ifInstruction, whileInstruction, elseEndInstruction, elseInstruction;
};

#endif
